package com.gragra.sampling.nonproj.structures.tests;
import static org.junit.Assert.*;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import java.util.ArrayList;
import org.junit.Test;
import com.gragra.sampling.PopulationProbabilityAssigner;
import com.gragra.sampling.ThreadedUniformAccess;
import com.gragra.sampling.nonproj.ConvertHeadedFactory;
import com.gragra.sampling.nonproj.ConvertHeadedStructure;
import com.gragra.sampling.nonproj.FixedParsesAssigner;
import com.gragra.sampling.nonproj.Uniform;
import com.gragra.sampling.nonproj.generators.CreateDependencyCorpus;
import com.gragra.sampling.nonproj.generators.projective.singleroot.CreateGibbsMHSingleRootProjective;
import com.gragra.sampling.nonproj.structures.projective.singleroot.SingleRootProjectiveDepdTree;
/**
 * 
 * @author Christoph Teichmann
 * 11.10.2013
 */
public class TestGibbsMHSingleRootProjective
{
	/**
	 * 
	 */
	private CreateDependencyCorpus cre = new CreateGibbsMHSingleRootProjective(new ConvertHeadedFactory());
	/**
	 * 
	 */
	private ThreadedUniformAccess	tua;
	/**
	 * 
	 */
	private SingleRootProjectiveDepdTree	tree;
	@Test
	public void testGetCurrentRoot()
	{
		tree = (SingleRootProjectiveDepdTree) cre.makeTree("0|0 1|1 2|2 3|3 4|4", 3, 0.1);
		tua = new ThreadedUniformAccess(3);
		Uniform uni = new Uniform(3);
		tree.initialize(uni, tua);
		for(int thread = 0;thread<3;++thread)
		{
			for(int i=0;i<tree.getLength();++i)
			{
				int head = tree.getHeadPosition(i, thread);
				if(head == tree.getRootPosition())
				{assertEquals(i,tree.getCurrentRoot(thread));}
			}
		}
	}
	@Test
	public void testResample1() throws InterruptedException
	{
		tree = (SingleRootProjectiveDepdTree) cre.makeTree("0|0 1|1 2|2 3|3 4|4", 3, 0.1);
		tua = new ThreadedUniformAccess(3);
		Uniform uni = new Uniform(3);
		tree.initialize(uni, tua);
		Thread[] threads = new Thread[3];
		for(int i=0;i<5000;++i)
		{
			for(int j=0;j<3;++j)
			{
				threads[j] = new TH(j, uni);
				threads[j].start();
			}
			for(Thread thread : threads)
			{thread.join();}
			tree.addSample();
		}
		Object2IntOpenHashMap<String> m = (((ConvertHeadedStructure) tree.getConverter()).getCounts());
		assertEquals(m.size(),143);
		double max = 0.0;
		for(String s : m.keySet())
		{
			double v1 = m.getInt(s);
			for(String t : m.keySet())
			{
				double v2 = m.getInt(t);
				max = Math.max(max, v1/v2);
			}
		}
		assertEquals(max,1.0,1.0);
	}
	/**
	 * 
	 * @param thread
	 * @return
	 */
	private boolean isSingleRooted(int thread)
	{
		int roots = 0;
		for(int i=0;i<this.tree.getLength();++i)
		{
			if(tree.getHeadPosition(i, thread)==tree.getRootPosition())
			{++roots;}
		}
		return roots==1;
	}
	@Test
	public void testResample2() throws InterruptedException
	{
		tree = (SingleRootProjectiveDepdTree) cre.makeTree("0|0 1|1 2|2 3|3 4|4", 5, 0.1);
		tua = new ThreadedUniformAccess(5);
		ArrayList<String> golds = new ArrayList<String>();
		golds.add("1 3 3 5 3");
		golds.add("2 2 5 2 2");
		FixedParsesAssigner fpa = new FixedParsesAssigner(5, 3.0, 2, golds);
		tree.initialize(fpa, tua);
		Thread[] threads = new Thread[5];
		for(int i=0;i<5000;++i)
		{
			for(int j=0;j<5;++j)
			{
				threads[j] = new TH(j, fpa);
				threads[j].start();
			}
			for(Thread thread : threads)
			{thread.join();}
			tree.addSample();
		}
		assertTrue(tree.getNumberSeen(golds.get(0))>0);
		double max = Math.max((double) tree.getNumberSeen(golds.get(0))/(double) tree.getNumberSeen(golds.get(1)), (double) tree.getNumberSeen(golds.get(1))/(double) tree.getNumberSeen(golds.get(0)));
		assertEquals(max,1.0,1.0);
	}
	/**
	 * 
	 * @param thread
	 * @return
	 */
	private boolean isProjective(int thread)
	{
		for(int i=0;i<tree.getLength();++i)
		{
			int head = tree.getHeadPosition(i, thread);
			int from = Math.min(i, head);
			int to = Math.max(head, i);
			for(int j=0;j<tree.getLength();++j)
			{
				head = tree.getHeadPosition(j, thread);
				if(j < from && head > from && to > head)
				{return false;}
				if(j>from&&((j<to && (head < from || head > to)) || (j>to && head < to && head > from)))
				{return false;}
			}
		}
		return true;
	}
	/**
	 * 
	 * @author Christoph Teichmann
	 * 16.10.2013
	 */
	private final class TH extends Thread
	{

		/**
		 * 
		 */
		private final int	thread;
		/**
		 * @param thread
		 * @param uni
		 */
		public TH(int thread, PopulationProbabilityAssigner uni)
		{
			super();
			this.thread = thread;
			this.uni = uni;
		}
		/**
		 * 
		 */
		private final PopulationProbabilityAssigner	uni;
		/* (non-Javadoc)
		 * @see java.lang.Thread#run()
		 */
		@Override
		public void run()
		{
				tree.resample(uni, 1.0, thread, tua);
				assertTrue(isProjective(thread));
				assertTrue(isSingleRooted(thread));
		}
	}
}